#include <QPainter>
#include <QMouseEvent>
#include <QtSvg>
#include <QVariantAnimation>
#include <cassert>
#include "TaskMenu.h"
#include "TaskItem.h"
#include "DataCenter.h"

static QColor progressColor(0, 200, 0);


TaskItem::TaskItem(QWidget *parent) : QWidget(parent), checkBox(this)
{
    setFixedSize(220, 56);
    m_drawHeight = height() / 2;
    m_drawWidth = -1;
    checkBox.setGeometry(10, 0, 150, 50);

    // this signal is not emitted if you call setChecked()
    connect(&checkBox, &QCheckBox::clicked, this, &TaskItem::onClicked);

    connect(DGuiApplicationHelper::instance(), &DGuiApplicationHelper::themeTypeChanged, this, &TaskItem::onThemeChanged);
    onThemeChanged(DGuiApplicationHelper::instance()->themeType());

    menu = new TaskMenu;
    connect(&menu->openSchedule, &QAction::triggered, this, &TaskItem::openSchedule);
    connect(&menu->setCountdownModeAction, &QAction::triggered, this, &TaskItem::onModeActionToggled);
    connect(&menu->setPiningModeAction, &QAction::triggered, this, &TaskItem::onModeActionToggled);
    connect(&menu->setNormalModeAction, &QAction::triggered, this, &TaskItem::onModeActionToggled);


}

TaskItem::~TaskItem()
{
    menu->deleteLater();
}

QSize TaskItem::minimumSizeHint() const
{
    return QSize(220, 56);
}

QSize TaskItem::sizeHint() const
{
    return QSize(220, 56);
}

void TaskItem::setTask(const ScheduleDataInfo &task)
{
    m_task = task;
    if (m_task.getRepetitionRule().getRuleId() != RepetitionRule::RRule_NONE)
        repeatHint = true;

    ExtendedData extData = DataCenter::instance().getExtendedData(m_task);
    countdownHint = extData.countdownHint;
    piningHint = extData.piningHint;
    checkBox.setChecked(extData.isChecked);

    refreshMode();
}

bool TaskItem::isChecked()
{
    return checkBox.isChecked();
}

TaskItem::Mode TaskItem::getMode()
{
    return m_mode;
}


QDateTime TaskItem::getBeginDateTime()
{
    return m_task.getBeginDateTime();
}

void TaskItem::refreshMode()
{
    Mode preMode = m_mode;
    Modifier preModifier = m_modifier;
    timerFlick = false;
    m_mode = NoMode;
    checkBox.setText("  " + m_task.getBeginDateTime().toString("MM.dd  hh:mm") + "\n  " + m_task.getTitleName());


    QDateTime currentDateTime = QDateTime::currentDateTime();
    QDateTime prepareDateTime;
    int remindNum = m_task.getRemindData().getRemindNum();
    if (remindNum == -1)
    {
        prepareDateTime = m_task.getBeginDateTime();
    }
    else if (m_task.getAllDay())
    {
        prepareDateTime = m_task.getBeginDateTime().addDays(-remindNum);
        m_mode = Bell;
    }
    else
    {
        prepareDateTime = m_task.getBeginDateTime().addSecs(-remindNum * 60);
        m_mode = Bell;
    }


    if (piningHint)
    {
        m_mode = Pining;
    }

    if (countdownHint)
    {
        if (currentDateTime < m_task.getBeginDateTime().addSecs(-60 * 60))
        {
            m_mode = CountdownHot;
        }
        else if (currentDateTime < m_task.getEndDateTime().addSecs(-5))
        {
            m_mode = CountdownTimer;
        }
//        else if (currentDateTime <= m_task.getEndDateTime().addSecs(60 * 5))
//        {
//            m_mode = CountdownProcess;
//        }
    }

    if (isChecked())
    {
        m_modifier = Check;
    }
    else if (currentDateTime > m_task.getEndDateTime())
    {
        m_modifier = Warn;
    }
    else if (currentDateTime > prepareDateTime)
    {
        m_modifier = Timer;
    }
    else
    {
        m_modifier = NoModifier;
    }

    if (m_modifier != preModifier || m_mode != preMode)
    {
        emit stateChanged();
        freshMenu();
    }

    update();
}

void TaskItem::freshMenu()
{
    menu->setCountdownModeAction.setVisible(false);
    menu->setPiningModeAction.setVisible(false);
    menu->setNormalModeAction.setVisible(false);
    if (!isChecked())
    {
        if (QDateTime::currentDateTime() < m_task.getBeginDateTime() && !countdownHint)
            menu->setCountdownModeAction.setVisible(true);

        if (!countdownHint && !piningHint)
            menu->setPiningModeAction.setVisible(true);

        if (countdownHint || piningHint)
            menu->setNormalModeAction.setVisible(true);
    }
}

void TaskItem::fadeAnimate()
{
    QColor fadedColor = m_backgroundColor;
    fadedColor.setAlpha(0);
    QColor bloomedColor = m_backgroundColor;
    bloomedColor.setAlpha(180);

    QVariantAnimation *animate = new QVariantAnimation(this);
    connect(animate, &QVariantAnimation::valueChanged, this, &TaskItem::onColorValueChanged);
    animate->setDuration(300);
    animate->setStartValue(bloomedColor);
    animate->setEndValue(fadedColor);
    connect(animate, &QVariantAnimation::finished, this, &TaskItem::faded);
    animate->start(QVariantAnimation::DeleteWhenStopped);
}

void TaskItem::bloomAnimate()
{
    QColor fadedColor = m_backgroundColor;
    fadedColor.setAlpha(0);
    QColor bloomedColor = m_backgroundColor;
    bloomedColor.setAlpha(180);

    QVariantAnimation *animate = new QVariantAnimation(this);
    connect(animate, &QVariantAnimation::valueChanged, this, &TaskItem::onColorValueChanged);
    animate->setDuration(300);
    animate->setStartValue(fadedColor);
    animate->setEndValue(bloomedColor);
    animate->start(QVariantAnimation::DeleteWhenStopped);
}

void TaskItem::progressAnimate()
{
    int duration = int(QDateTime::currentDateTime().msecsTo(m_task.getBeginDateTime()));
    QVariantAnimation *animate = new QVariantAnimation(this);
    connect(animate, &QVariantAnimation::valueChanged, this, [=](QVariant value){
        int progress = value.toInt();
        m_drawWidth = width() * progress / duration;
        update();
    });

    animate->setStartValue(0);
    animate->setEndValue(duration);
    animate->setDuration(duration);
    animate->start(QVariantAnimation::DeleteWhenStopped);
    progressHint = true;

    duration = int(QDateTime::currentDateTime().msecsTo(m_task.getBeginDateTime()));
    QTimer::singleShot(duration, this, [=](){
        progressHint = false;
        m_backgroundColor = QColor(200, 0, 0, 180);
        onCountdown();
        update();
    });

    QTimer::singleShot(duration + 3000, this, [=](){
        onThemeChanged(DGuiApplicationHelper::instance()->themeType());
        update();
    });


}

void TaskItem::onCountdown()
{
    if (m_mode == CountdownTimer || m_mode == CountdownProcess)
    {
        timerFlick = !timerFlick;
        int minutes;
        int seconds;
        int mseconds = int(QDateTime::currentDateTime().msecsTo(m_task.getBeginDateTime())) + 1000; // 倒计时为0表示开始，1～0秒算在之前

        if (mseconds > 0)
        {
            minutes = mseconds / 1000 / 60;
            seconds = (mseconds / 1000) % 60;
            if (seconds < 10 && m_mode == CountdownTimer)
            {
                m_mode = CountdownProcess;
                progressAnimate();
                emit stateChanged();
            }
        }
        else
        {
            minutes = seconds = 0;
        }
        checkBox.setText(QString("  %1:%2 => %3\n  %4").
                             arg(minutes, 2, 10, QChar('0')).
                             arg(seconds, 2, 10, QChar('0')).
                             arg(m_task.getBeginDateTime().toString("hh:mm::ss")).
                             arg(m_task.getTitleName()));
        update();

    }
}


void TaskItem::paintEvent(QPaintEvent *event)
{
    QPainter painter(this);
    painter.setRenderHint(QPainter::Antialiasing);
    painter.setPen(Qt::NoPen);
    QColor color = m_backgroundColor;
    color.setAlpha(m_alpha);
    painter.setBrush(color);
    painter.drawRoundedRect(0, height() / 2 - m_drawHeight, width(), 2 * m_drawHeight, 8, 8);

    if (progressHint)
    {
        painter.setBrush(progressColor);
        painter.drawRoundedRect(0, height() / 2 - m_drawHeight, m_drawWidth, 2 * m_drawHeight, 8, 8);
        if (8 <= m_drawWidth && m_drawWidth <= width() - 8)
        {
            painter.drawRect(m_drawWidth - 8, height() / 2 - m_drawHeight, 8, 2 * m_drawHeight);
        }
    }

    static QSvgRenderer bellSvg(QString(":/pics/bell.svg"));
    static QSvgRenderer repeatSvg(QString(":/pics/repeat.svg"));
    static QSvgRenderer warnSvg(QString(":/pics/warn.svg"));
    static QSvgRenderer timerSvg(QString(":/pics/timer.svg"));
    static QSvgRenderer pinSvg(QString(":/pics/pin.svg"));
    static QSvgRenderer hotSvg(QString(":/pics/hot.svg"));

    QRect rect1(width() - 30, 5, 20, 20);
    QRect rect2 = rect1.translated(-25, 0);
    QRect rect3 = rect1.translated(0, 25);

    if (m_mode == CountdownHot)
        hotSvg.render(&painter, rect1);
    else if (timerFlick && (m_mode == CountdownTimer || m_mode == CountdownProcess))
        timerSvg.render(&painter, rect1);
    else if (m_mode == Pining)
        pinSvg.render(&painter, rect1);
    else if (m_mode == Bell)
        bellSvg.render(&painter, rect1);


    if (m_modifier == Warn)
    {
        warnSvg.render(&painter, rect2);
    }
    else if (m_modifier == Timer && m_mode != CountdownHot && m_mode != CountdownTimer)
    {
        timerSvg.render(&painter, rect2);
    }

    if (repeatHint)
    {
        repeatSvg.render(&painter, rect3);
    }
}

void TaskItem::mousePressEvent(QMouseEvent *event)
{
    event->accept();
}

void TaskItem::mouseReleaseEvent(QMouseEvent *event)
{
    if (event->button() == Qt::RightButton)
    {
        menu->exec(event->globalPos());
    }
    event->accept();
}

void TaskItem::mouseMoveEvent(QMouseEvent *event)
{
    event->accept();
}


void TaskItem::onThemeChanged(DGuiApplicationHelper::ColorType type)
{
    if (type == DGuiApplicationHelper::ColorType::DarkType)
    {
        m_backgroundColor = QColor(0, 0, 0, 180);
    }
    else
    {
        m_backgroundColor = QColor(255, 255,255, 180);
    }
    m_alpha = m_backgroundColor.alpha();
}

void TaskItem::onColorValueChanged(const QVariant &color)
{
    m_alpha = color.value<QColor>().alpha();
    m_drawHeight = m_alpha * height() / 180 / 2; // 180 is alpha of the color
    update();
}

void TaskItem::openSchedule()
{
    DataCenter::instance().OpenSchedule(ScheduleDataInfo::ScheduleToJsonStr(m_task));
}

void TaskItem::onModeActionToggled()
{
    QAction *modeAction = qobject_cast<QAction *>(sender());
    assert(modeAction);
    if (modeAction == &menu->setCountdownModeAction)
    {
        countdownHint = true;
        piningHint = false;
    }
    if (modeAction == &menu->setPiningModeAction)
    {
        piningHint = true;
        countdownHint = false;
    }
    if (modeAction == &menu->setNormalModeAction)
        countdownHint = piningHint = false;

    refreshMode();
    extDataChanged();
}

void TaskItem::onClicked(bool state)
{
    // this signal is not emitted if you call setChecked()
    countdownHint = piningHint = false;
    refreshMode();
    extDataChanged();;
}

void TaskItem::extDataChanged()
{
    ExtendedData extData(isChecked(), piningHint, countdownHint);
    extData.id = DataID(m_task.getID(), m_task.getRecurID(), m_task.getTitleName());
    DataCenter::instance().setExtendedData(m_task, extData);
}

